home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTVMS_WaisUI.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  58.6 KB  |  2,433 lines

  1. /*                            HTVMS_WAISUI.c
  2. **
  3. **    Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu)
  4. **
  5. **    30-May-1994 FM    Initial version.
  6. **
  7. /*----------------------------------------------------------------------*/
  8.  
  9. /*
  10. **    Routines originally from UI.c -- FM
  11. **
  12. **----------------------------------------------------------------------*/
  13. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  14.    No guarantees or restrictions.  See the readme file for the full standard
  15.    disclaimer.
  16.  
  17.    Brewster@think.com
  18. */
  19.  
  20. /* 
  21.  * this is a simple ui toolkit for building other ui's on top.
  22.  * -brewster
  23.  * 
  24.  * top level functions:
  25.  *   generate_search_apdu
  26.  *   generate_retrieval_apdu
  27.  *   interpret_message
  28.  *
  29.  */
  30.  
  31. /* to do:
  32.  *   generate multiple queries for long documents.
  33.  *     this will crash if the file being retrieved is larger than 100k.
  34.  *   do log_write()
  35.  *   
  36.  */
  37.  
  38. #include "HTUtils.h"
  39. #include "tcp.h"
  40. #include "HTVMS_WaisUI.h"
  41. #include "HTVMS_WaisProt.h"
  42. /*#include <stdio> included by HTUtils.h -- FM */
  43. #include <string.h>
  44. #include <ctype.h>
  45. #include <math.h>
  46. #include <stdarg.h>
  47.  
  48. #include "LYexit.h"
  49. #include "LYLeaks.h"
  50.  
  51. void
  52. log_write(s)
  53. char *s;
  54. {
  55.     return;
  56. }
  57.  
  58. /*----------------------------------------------------------------------*/
  59.  
  60. /* returns a pointer in the buffer of the first free byte.
  61.    if it overflows, then NULL is returned 
  62.  */
  63. char *
  64. generate_search_apdu(buff,
  65.              buff_len,
  66.              seed_words,
  67.              database_name,
  68.              docobjs,
  69.              maxDocsRetrieved)
  70. char* buff;     /* buffer to hold the apdu */
  71. long *buff_len;    /* length of the buffer changed to reflect new data written */
  72. char *seed_words;    /* string of the seed words */
  73. char *database_name;
  74. DocObj** docobjs;
  75. long maxDocsRetrieved;
  76. {
  77.   /* local variables */
  78.  
  79.   SearchAPDU *search3;
  80.   char  *end_ptr;
  81.   static char *database_names[2] = {"", 0};
  82.   any refID;
  83.   WAISSearch *query;
  84.   refID.size = 1;
  85.   refID.bytes = "3";
  86.  
  87.   database_names[0] = database_name;
  88.   query = makeWAISSearch(seed_words,
  89.                          docobjs, /* DocObjsPtr */
  90.                          0,
  91.                          1,     /* DateFactor */
  92.                          0,     /* BeginDateRange */
  93.                          0,     /* EndDateRange */
  94.                          maxDocsRetrieved
  95.                          );
  96.  
  97.   search3 = makeSearchAPDU(30, 
  98.                5000, /* should be large */
  99.                30,
  100.                            1,    /* replace indicator */
  101.                            "",    /* result set name */
  102.                            database_names, /* database name */   
  103.                            QT_RelevanceFeedbackQuery, /* query_type */
  104.                            0,   /* element name */
  105.                            NULL, /* reference ID */
  106.                            query);
  107.  
  108.   end_ptr = writeSearchAPDU(search3, buff, buff_len);
  109.  
  110.   CSTFreeWAISSearch(query);
  111.   freeSearchAPDU(search3);
  112.   return(end_ptr);
  113. }
  114.  
  115. /*----------------------------------------------------------------------*/
  116.  
  117. /* returns a pointer into the buffer of the next free byte.
  118.    if it overflowed, then NULL is returned
  119.  */
  120.  
  121. char *
  122. generate_retrieval_apdu(buff,
  123.             buff_len,
  124.             docID,
  125.             chunk_type,
  126.             start,
  127.             end,
  128.             type,
  129.             database_name)
  130. char *buff;
  131. long *buff_len;    /* length of the buffer changed to reflect new data written */
  132. any *docID;
  133. long chunk_type;
  134. long start;
  135. long end;
  136. char *type;
  137. char *database_name;
  138. {
  139.   SearchAPDU *search;
  140.   char  *end_ptr;
  141.  
  142.   static char *database_names[2];
  143.   static char *element_names[3];
  144.   any refID;
  145.  
  146.   DocObj *DocObjs[2];
  147.   any *query;            /* changed from char* by brewster */
  148.  
  149.   if(NULL == type)
  150.     type = s_strdup("TEXT");
  151.  
  152.   database_names[0] = database_name;
  153.   database_names[1] = NULL;
  154.  
  155.   element_names[0] = " ";
  156.   element_names[1] = ES_DocumentText;
  157.   element_names[2] = NULL;
  158.  
  159.   refID.size = 1;
  160.   refID.bytes = "3";
  161.   
  162.   switch(chunk_type){
  163.   case CT_line: 
  164.     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  165.     break;
  166.   case CT_byte:
  167.     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  168.     break;
  169.   }
  170.   DocObjs[1] = NULL;
  171.  
  172.   query = makeWAISTextQuery(DocObjs);   
  173.   search = makeSearchAPDU( 10, 16, 15, 
  174.               1,    /* replace indicator */
  175.               "FOO", /* result set name */
  176.               database_names, /* database name */   
  177.               QT_TextRetrievalQuery, /* query_type */
  178.               element_names, /* element name */
  179.               &refID, /* reference ID */
  180.               query);
  181.   end_ptr = writeSearchAPDU(search, buff, buff_len);
  182.   CSTFreeWAISTextQuery(query);
  183.   freeSearchAPDU(search);
  184.   return(end_ptr);
  185. }
  186.  
  187. /*----------------------------------------------------------------------*/
  188.  
  189. /* this is a safe version of unix 'read' it does all the checking
  190.  * and looping necessary
  191.  * to those trying to modify the transport code to use non-UNIX streams:
  192.  *  This is the function to modify!
  193.  */
  194. long read_from_stream(d,buf,nbytes)
  195. int d;                /* this is the stream */
  196. char *buf;
  197. long nbytes;
  198. {
  199.   long didRead;
  200.   long toRead = nbytes;
  201.   long totalRead = 0;        /* paranoia */
  202.  
  203.   while (toRead > 0){
  204.     didRead = NETREAD (d, buf, (int)toRead);
  205.     if(didRead == HT_INTERRUPTED)
  206.       return(HT_INTERRUPTED);
  207.     if(didRead == -1)        /* error*/
  208.       return(-1);
  209.     if(didRead == 0)        /* eof */
  210.       return(-2);        /* maybe this should return 0? */
  211.     toRead -= didRead;
  212.     buf += didRead;
  213.     totalRead += didRead;
  214.   }
  215.   if(totalRead != nbytes)    /* we overread for some reason */
  216.     return(- totalRead);    /* bad news */    
  217.   return(totalRead);
  218. }
  219.  
  220. /*----------------------------------------------------------------------*/
  221.  
  222. /* returns the length of the response, 0 if an error */
  223.  
  224. long 
  225. transport_message(connection,
  226.           request_message,
  227.           request_length,
  228.           response_message,
  229.           response_buffer_length)
  230. int connection;
  231. char *request_message;
  232. long request_length;
  233. char *response_message;
  234. long response_buffer_length;
  235. {
  236.   WAISMessage header;
  237.   long response_length;
  238.   int rv;
  239.  
  240.   
  241.   /* Write out message. Read back header. Figure out response length. */
  242.   
  243.   if( request_length + HEADER_LENGTH !=
  244.       NETWRITE(connection,request_message,
  245.              (int)( request_length +HEADER_LENGTH)) )
  246.     return 0;
  247.  
  248.   /* read for the first '0' */
  249.  
  250.   while(1){
  251.     rv = read_from_stream(connection, response_message, 1);
  252.     if (rv == HT_INTERRUPTED)
  253.       return HT_INTERRUPTED;
  254.     if (rv < 0)
  255.       return 0;
  256.     if('0' == response_message[0])
  257.       break;
  258.   }
  259.  
  260.   rv = read_from_stream(connection, response_message + 1, HEADER_LENGTH -1);
  261.   if (rv == HT_INTERRUPTED)
  262.     return HT_INTERRUPTED;
  263.   if (rv < 0)
  264.     return 0;
  265.  
  266.   readWAISPacketHeader(response_message, &header);
  267.   {
  268.     char length_array[11];
  269.     strncpy(length_array, header.msg_len, 10);
  270.     length_array[10] = '\0';
  271.     response_length = atol(length_array);
  272.     /*
  273.       if(verbose){
  274.       printf("WAIS header: '%s' length_array: '%s'\n", 
  275.       response_message, length_array);
  276.       }
  277.       */
  278.     if(response_length > response_buffer_length){
  279.       /* we got a message that is too long, therefore empty the message out,
  280.      and return 0 */
  281.       long i;
  282.       for(i = 0; i < response_length; i++){
  283.     rv = read_from_stream(connection, 
  284.                   response_message + HEADER_LENGTH,
  285.                   1);
  286.     if (rv == HT_INTERRUPTED)
  287.       return HT_INTERRUPTED;
  288.     if (rv < 0)
  289.       return 0;
  290.       }
  291.       return(0);
  292.     }
  293.   }
  294.   rv = read_from_stream(connection, 
  295.             response_message + HEADER_LENGTH,
  296.             response_length);
  297.   if (rv == HT_INTERRUPTED)
  298.     return HT_INTERRUPTED;
  299.   if (rv < 0)
  300.     return 0;
  301.   return(response_length);
  302. }
  303.  
  304. /*----------------------------------------------------------------------*/
  305.  
  306. /* returns the number of bytes writen.  0 if an error */
  307. long
  308. interpret_message(request_message,request_length,
  309.           response_message,
  310.           response_buffer_length,
  311.           connection,
  312.           verbose)
  313. char *request_message;
  314. long request_length; /* length of the buffer */
  315. char *response_message;
  316. long response_buffer_length;
  317. int connection;
  318. boolean verbose;
  319. {
  320.   long response_length;
  321.  
  322.   /* ?
  323.   if(verbose){
  324.     printf ("sending");
  325.     if(hostname_internal && strlen(hostname_internal) > 0)
  326.       printf(" to host %s", hostname_internal);
  327.     if(service_name && strlen(service_name) > 0)
  328.       printf(" for service %s", service_name);
  329.     printf("\n");
  330.     twais_dsply_rsp_apdu(request_message + HEADER_LENGTH, 
  331.              request_length);
  332.   }
  333.  
  334.   */
  335.  
  336.   writeWAISPacketHeader(request_message,
  337.             request_length,
  338.             (long)'z',    /* Z39.50 */
  339.             "wais      ", /* server name */
  340.             (long)NO_COMPRESSION,    /* no compression */
  341.             (long)NO_ENCODING,(long)HEADER_VERSION);
  342.   if(connection != 0) {
  343.     response_length = transport_message(connection, request_message,
  344.                     request_length,
  345.                     response_message,
  346.                     response_buffer_length);
  347.     if (response_length == HT_INTERRUPTED)
  348.       return(HT_INTERRUPTED);
  349.   }
  350.   else
  351.       return(0);
  352.  
  353.   return(response_length);
  354. }
  355.  
  356. /*----------------------------------------------------------------------*/
  357.  
  358. /* modifies the string to exclude all seeker codes. sets length to
  359.    the new length. */
  360. char *delete_seeker_codes(string,length)
  361. char *string;
  362. long *length;
  363. {
  364.   long original_count; /* index into the original string */
  365.   long new_count = 0; /* index into the collapsed string */
  366.   for(original_count = 0; original_count < *length; original_count++){
  367.     if(27 == string[original_count]){
  368.       /* then we have an escape code */
  369.       /* if the next letter is '(' or ')', then ignore two letters */
  370.       if('(' == string[original_count + 1] ||
  371.     ')' == string[original_count + 1])
  372.      original_count += 1;    /* it is a term marker */
  373.       else original_count += 4; /* it is a paragraph marker */
  374.     }
  375.     else string[new_count++] = string[original_count];
  376.   }
  377.   *length = new_count;
  378.   return(string);
  379. }
  380.   
  381. /*----------------------------------------------------------------------*/
  382.  
  383. /* returns a pointer to a string with good stuff */
  384. char *trim_junk(headline)
  385. char *headline;
  386. {
  387.   long length = strlen(headline) + 1; /* include the trailing null */
  388.   long i;
  389.   headline = delete_seeker_codes(headline, &length);
  390.   /* delete leading spaces */
  391.   for(i=0; i < strlen(headline); i++){
  392.     if(isprint(headline[i])){
  393.       break;
  394.     }
  395.   }
  396.   headline = headline + i;
  397.   /* delete trailing stuff */
  398.   for(i=strlen(headline) - 1 ; i > 0; i--){
  399.     if(isprint(headline[i])){
  400.       break;
  401.     }
  402.     headline[i] = '\0';
  403.   }
  404.   return(headline);
  405. }
  406.  
  407. /*----------------------------------------------------------------------*/
  408.  
  409.  
  410. /*
  411. **    Routines originally from ZProt.c -- FM
  412. **
  413. **----------------------------------------------------------------------*/
  414. /* WIDE AREA INFORMATION SERVER SOFTWARE:`
  415.    No guarantees or restrictions.  See the readme file for the full standard
  416.    disclaimer.    
  417.   
  418.    3.26.90    Harry Morris, morris@think.com
  419.    3.30.90  Harry Morris - Changed any->bits to any->bytes
  420.    4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  421. */
  422.  
  423. #define RESERVE_SPACE_FOR_HEADER(spaceLeft)        \
  424.     *spaceLeft -= HEADER_LEN;
  425.     
  426. #define RELEASE_HEADER_SPACE(spaceLeft)            \
  427.     if (*spaceLeft > 0)                \
  428.       *spaceLeft += HEADER_LEN;
  429.     
  430. /*----------------------------------------------------------------------*/
  431.  
  432. InitResponseAPDU* 
  433. makeInitResponseAPDU(result,
  434.              search,
  435.              present,
  436.              deleteIt,
  437.              accessControl,
  438.              resourceControl,
  439.              prefSize,
  440.              maxMsgSize,
  441.              auth,
  442.              id,
  443.              name,
  444.              version,
  445.              refID,
  446.              userInfo)
  447. boolean result;
  448. boolean search;
  449. boolean present;
  450. boolean deleteIt;
  451. boolean accessControl;
  452. boolean resourceControl;
  453. long prefSize;
  454. long maxMsgSize;
  455. char* auth;
  456. char* id;
  457. char* name;
  458. char* version;
  459. any* refID;
  460. void* userInfo;
  461. /* build an initResponse APDU with user specified information */
  462.   InitResponseAPDU* init = (InitResponseAPDU*)s_malloc((size_t)sizeof(InitResponseAPDU));
  463.  
  464.   init->PDUType = initResponseAPDU;
  465.   init->Result = result;
  466.   init->willSearch = search;
  467.   init->willPresent = present;
  468.   init->willDelete = deleteIt;
  469.   init->supportAccessControl = accessControl;
  470.   init->supportResourceControl = resourceControl;
  471.   init->PreferredMessageSize = prefSize;
  472.   init->MaximumRecordSize = maxMsgSize;
  473.   init->IDAuthentication = s_strdup(auth);
  474.   init->ImplementationID = s_strdup(id);
  475.   init->ImplementationName = s_strdup(name);
  476.   init->ImplementationVersion = s_strdup(version);
  477.   init->ReferenceID = duplicateAny(refID);
  478.   init->UserInformationField = userInfo; /* not copied! */
  479.   
  480.   return(init);
  481. }
  482.  
  483. /*----------------------------------------------------------------------*/
  484.  
  485. void 
  486. freeInitResponseAPDU(init)
  487. InitResponseAPDU* init;
  488. /* free an initAPDU */
  489. {
  490.   s_free(init->IDAuthentication);
  491.   s_free(init->ImplementationID);
  492.   s_free(init->ImplementationName);
  493.   s_free(init->ImplementationVersion);
  494.   freeAny(init->ReferenceID);
  495.   s_free(init);
  496. }
  497.  
  498. /*----------------------------------------------------------------------*/
  499.  
  500. char* 
  501. writeInitResponseAPDU(init,buffer,len)
  502. InitResponseAPDU* init;
  503. char* buffer;
  504. long* len;
  505. /* write the initResponse to a buffer, adding system information */
  506.   char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */
  507.   long size;
  508.   bit_map* optionsBM = NULL;
  509.  
  510.   RESERVE_SPACE_FOR_HEADER(len);
  511.   
  512.   buf = writePDUType(init->PDUType,buf,len);
  513.   buf = writeBoolean(init->Result,buf,len);
  514.   buf = writeProtocolVersion(buf,len);
  515.   
  516.   optionsBM = makeBitMap((unsigned long)5,init->willSearch,init->willPresent,
  517.                          init->willDelete,init->supportAccessControl,
  518.                          init->supportResourceControl);
  519.   buf = writeBitMap(optionsBM,DT_Options,buf,len);
  520.   freeBitMap(optionsBM);
  521.  
  522.   buf = writeNum(init->PreferredMessageSize,DT_PreferredMessageSize,buf,len);
  523.   buf = writeNum(init->MaximumRecordSize,DT_MaximumRecordSize,buf,len);
  524.   buf = writeString(init->IDAuthentication,DT_IDAuthentication,buf,len);
  525.   buf = writeString(init->ImplementationID,DT_ImplementationID,buf,len);
  526.   buf = writeString(init->ImplementationName,DT_ImplementationName,buf,len);
  527.   buf = writeString(init->ImplementationVersion,DT_ImplementationVersion,buf,len);
  528.   buf = writeAny(init->ReferenceID,DT_ReferenceID,buf,len);
  529.   
  530.   /* go back and write the header-length-indicator */
  531.   RELEASE_HEADER_SPACE(len);
  532.   size = buf - buffer - HEADER_LEN; 
  533.   writeBinaryInteger(size,HEADER_LEN,buffer,len);
  534.  
  535.   if (init->UserInformationField != NULL)
  536.     buf = writeInitResponseInfo(init,buf,len);   
  537.     
  538.   return(buf);
  539. }
  540.  
  541. /*----------------------------------------------------------------------*/
  542.  
  543. char* 
  544. readInitResponseAPDU(init,buffer)
  545. InitResponseAPDU** init;
  546. char* buffer;
  547. {
  548.   char* buf = buffer;
  549.   boolean search,present,delete,accessControl,resourceControl;
  550.   long prefSize,maxMsgSize;
  551.   char *auth,*id,*name,*version;
  552.   long size; 
  553.   pdu_type pduType;
  554.   bit_map* versionBM = NULL;
  555.   bit_map* optionsBM = NULL;
  556.   boolean result;
  557.   any *refID = NULL;
  558.   void* userInfo = NULL;
  559.   
  560.   auth = id = name = version = NULL;
  561.   refID = NULL;
  562.   
  563.   /* read required part */
  564.   buf = readBinaryInteger(&size,HEADER_LEN,buf); 
  565.   buf = readPDUType(&pduType,buf);
  566.   buf = readBoolean(&result,buf);
  567.   buf = readBitMap(&versionBM,buf); 
  568.   buf = readBitMap(&optionsBM,buf);
  569.   buf = readNum(&prefSize,buf);
  570.   buf = readNum(&maxMsgSize,buf);
  571.   
  572.   /* decode optionsBM */
  573.   search = bitAtPos(0,optionsBM);
  574.   present = bitAtPos(1,optionsBM);
  575.   delete = bitAtPos(2,optionsBM);
  576.   accessControl = bitAtPos(3,optionsBM);
  577.   resourceControl = bitAtPos(4,optionsBM);
  578.   
  579.   /* read optional part */
  580.   while (buf < (buffer + size + HEADER_LEN)) 
  581.     { data_tag tag = peekTag(buf);
  582.       switch (tag)
  583.     { case DT_IDAuthentication:
  584.         buf = readString(&auth,buf);
  585.         break;
  586.       case DT_ImplementationID:
  587.         buf = readString(&id,buf);
  588.         break;
  589.       case DT_ImplementationName:
  590.         buf = readString(&name,buf);
  591.         break;
  592.       case DT_ImplementationVersion:
  593.         buf = readString(&version,buf);
  594.         break;
  595.       case DT_ReferenceID:
  596.         buf = readAny(&refID,buf);
  597.         break;
  598.       default:
  599.         freeBitMap(versionBM);
  600.         freeBitMap(optionsBM);
  601.         s_free(auth);
  602.         s_free(id);
  603.         s_free(name);
  604.         s_free(version);
  605.         freeAny(refID);
  606.         REPORT_READ_ERROR(buf);
  607.         break;
  608.       }
  609.     }
  610.  
  611.   buf = readInitResponseInfo(&userInfo,buf);
  612.   if (buf == NULL)
  613.     { freeBitMap(versionBM);
  614.       freeBitMap(optionsBM);
  615.       s_free(auth);
  616.       s_free(id);
  617.       s_free(name);
  618.       s_free(version);
  619.       freeAny(refID);
  620.     }
  621.   RETURN_ON_NULL(buf);
  622.   
  623.   /* construct the basic init object */
  624.   *init = makeInitResponseAPDU(result,
  625.                    search,present,delete,accessControl,resourceControl,
  626.                    prefSize,maxMsgSize,auth,id,name,version,refID,userInfo);
  627.                                           
  628.   freeBitMap(versionBM);
  629.   freeBitMap(optionsBM);
  630.   s_free(auth);
  631.   s_free(id);
  632.   s_free(name);
  633.   s_free(version);
  634.   freeAny(refID);
  635.   
  636.   return(buf);
  637. }
  638.  
  639. /*----------------------------------------------------------------------*/
  640.  
  641. InitResponseAPDU* 
  642. replyToInitAPDU(init,result,userInfo)
  643. InitAPDU* init;
  644. boolean result;
  645. void* userInfo;
  646. /* respond to an init message in the default way - echoing back
  647.    the init info 
  648.  */
  649. {
  650.   InitResponseAPDU* initResp;
  651.   initResp = makeInitResponseAPDU(result,
  652.                   init->willSearch,init->willPresent,init->willDelete,
  653.                   init->supportAccessControl,init->supportResourceControl,
  654.                   init->PreferredMessageSize,init->MaximumRecordSize,
  655.                   init->IDAuthentication,defaultImplementationID(),defaultImplementationName(),
  656.                   defaultImplementationVersion(),
  657.                   init->ReferenceID,userInfo);
  658.   return(initResp);
  659. }
  660.  
  661. /*----------------------------------------------------------------------*/
  662.  
  663. SearchAPDU* 
  664. makeSearchAPDU(small,
  665.            large,
  666.            medium,
  667.            replace,
  668.            name,
  669.            databases,
  670.            type,
  671.            elements,
  672.            refID,
  673.            queryInfo)
  674. long small;
  675. long large;
  676. long medium;
  677. boolean replace;
  678. char* name;
  679. char** databases;
  680. char* type;
  681. char** elements;
  682. any* refID;
  683. void* queryInfo;
  684. {
  685.   char* ptr = NULL;
  686.   long i;
  687.   SearchAPDU* query = (SearchAPDU*)s_malloc((size_t)sizeof(SearchAPDU));
  688.   query->PDUType = searchAPDU;
  689.   query->SmallSetUpperBound = small;
  690.   query->LargeSetLowerBound = large;
  691.   query->MediumSetPresentNumber = medium;
  692.   query->ReplaceIndicator = replace;
  693.   query->ResultSetName = s_strdup(name);
  694.   query->DatabaseNames = NULL; 
  695.   if (databases != NULL)
  696.     { for (i = 0, ptr = databases[i]; ptr != NULL; ptr = databases[++i])
  697.     { if (query->DatabaseNames == NULL)
  698.         query->DatabaseNames = (char**)s_malloc((size_t)(sizeof(char*) * 2));
  699.         else
  700.           query->DatabaseNames = (char**)s_realloc((char*)query->DatabaseNames,
  701.                            (size_t)(sizeof(char*) * (i + 2)));
  702.         query->DatabaseNames[i] = s_strdup(ptr);
  703.         query->DatabaseNames[i+1] = NULL;
  704.       }
  705.       }
  706.   query->QueryType = s_strdup(type);
  707.   query->ElementSetNames = NULL; 
  708.   if (elements != NULL)
  709.     { for (i = 0, ptr = elements[i]; ptr != NULL; ptr = elements[++i])
  710.     { if (query->ElementSetNames == NULL)
  711.         query->ElementSetNames = (char**)s_malloc((size_t)(sizeof(char*) * 2));
  712.         else
  713.           query->ElementSetNames = (char**)s_realloc((char*)query->ElementSetNames,
  714.                              (size_t)(sizeof(char*) * (i + 2)));
  715.         query->ElementSetNames[i] = s_strdup(ptr);
  716.         query->ElementSetNames[i+1] = NULL;
  717.       }
  718.       }
  719.   query->ReferenceID = duplicateAny(refID);
  720.   query->Query = queryInfo;    /* not copied! */
  721.   return(query);
  722. }
  723.  
  724. /*----------------------------------------------------------------------*/
  725.  
  726. void 
  727. freeSearchAPDU(query)
  728. SearchAPDU* query;
  729. {
  730.   s_free(query->ResultSetName);
  731.   s_free(query->QueryType);
  732.   doList((void**)query->DatabaseNames,fs_free); /* can't use the macro here ! */
  733.   s_free(query->DatabaseNames);
  734.   doList((void**)query->ElementSetNames,fs_free); /* can't use the macro here ! */
  735.   s_free(query->ElementSetNames);
  736.   freeAny(query->ReferenceID);
  737.   s_free(query);
  738. }
  739.  
  740. /*----------------------------------------------------------------------*/
  741.  
  742. #define DB_DELIMITER     "\037"     /* hex 1F occurs between each database name */
  743. #define ES_DELIMITER_1     "\037"     /* separates database name from element name */
  744. #define ES_DELIMITER_2     "\036"     /* hex 1E separates <db,es> groups from one another */
  745.  
  746. char* 
  747. writeSearchAPDU(query,buffer,len)
  748. SearchAPDU* query;
  749. char* buffer;
  750. long* len;
  751.   char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */
  752.   long size,i;
  753.   char* ptr = NULL;
  754.   char* scratch = NULL;
  755.  
  756.   RESERVE_SPACE_FOR_HEADER(len);
  757.   
  758.   buf = writePDUType(query->PDUType,buf,len);
  759.   buf = writeBinaryInteger(query->SmallSetUpperBound,(size_t)3,buf,len);
  760.   buf = writeBinaryInteger(query->LargeSetLowerBound,(size_t)3,buf,len);
  761.   buf = writeBinaryInteger(query->MediumSetPresentNumber,(size_t)3,buf,len);
  762.   buf = writeBoolean(query->ReplaceIndicator,buf,len);
  763.   buf = writeString(query->ResultSetName,DT_ResultSetName,buf,len);
  764.   /* write database names */
  765.   if (query->DatabaseNames != NULL)
  766.     { for (i = 0,scratch = NULL, ptr = query->DatabaseNames[i]; ptr != NULL; ptr = query->DatabaseNames[++i])
  767.     { if (scratch == NULL)
  768.         scratch = s_strdup(ptr);
  769.         else
  770.       { size_t newScratchSize = (size_t)(strlen(scratch) + strlen(ptr) + 2);
  771.         scratch = (char*)s_realloc(scratch,newScratchSize);
  772.         s_strncat(scratch,DB_DELIMITER,2,newScratchSize);
  773.         s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize);
  774.       }
  775.       }
  776.     buf = writeString(scratch,DT_DatabaseNames,buf,len);
  777.     s_free(scratch);
  778.       }
  779.   buf = writeString(query->QueryType,DT_QueryType,buf,len);
  780.   /* write element set names */
  781.   if (query->ElementSetNames != NULL)
  782.     { for (i = 0,scratch = NULL, ptr = query->ElementSetNames[i]; ptr != NULL; ptr = query->ElementSetNames[++i])
  783.     { if (scratch == NULL)
  784.         { if (query->ElementSetNames[i+1] == NULL) /* there is a single element set name */
  785.         { scratch = (char*)s_malloc((size_t)strlen(ptr) + 2);
  786.           strncpy(scratch,ES_DELIMITER_1,2);
  787.           s_strncat(scratch,ptr,strlen(ptr) + 1,strlen(ptr) + 2);
  788.         }
  789.         else        /* this is the first of a series of element set names */
  790.           { size_t newScratchSize = (size_t)(strlen(ptr) + strlen(query->ElementSetNames[i + 1]) + 2);
  791.         scratch = s_strdup(ptr); /* the database name */
  792.         ptr = query->ElementSetNames[++i]; /* the element set name */
  793.         scratch = (char*)s_realloc(scratch,newScratchSize);
  794.         s_strncat(scratch,ES_DELIMITER_1,2,newScratchSize);
  795.         s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize); 
  796.           }
  797.           }
  798.         else
  799.       { char* esPtr = query->ElementSetNames[++i]; /* the element set name */
  800.         size_t newScratchSize = (size_t)(strlen(scratch) + strlen(ptr) + strlen(esPtr) + 3);
  801.         scratch = (char*)s_realloc(scratch,newScratchSize);
  802.         s_strncat(scratch,ES_DELIMITER_2,2,newScratchSize);
  803.         s_strncat(scratch,ptr,strlen(ptr) + 1,newScratchSize);
  804.         s_strncat(scratch,ES_DELIMITER_1,2,newScratchSize);
  805.         s_strncat(scratch,esPtr,strlen(esPtr) + 1,newScratchSize); 
  806.       }
  807.       }
  808.     buf = writeString(scratch,DT_ElementSetNames,buf,len);
  809.     s_free(scratch);
  810.       }                        
  811.   buf = writeAny(query->ReferenceID,DT_ReferenceID,buf,len);
  812.     
  813.   /* go back and write the header-length-indicator */
  814.   RELEASE_HEADER_SPACE(len);
  815.   size = buf - buffer - HEADER_LEN; 
  816.   writeBinaryInteger(size,HEADER_LEN,buffer,len);
  817.  
  818.   if (query->Query != NULL)
  819.     buf = writeSearchInfo(query,buf,len);    
  820.     
  821.   return(buf);
  822. }
  823.  
  824. /*----------------------------------------------------------------------*/
  825.  
  826. SearchResponseAPDU* 
  827. makeSearchResponseAPDU(result,count,recordsReturned,nextPos,resultStatus,
  828.                presentStatus,refID,records)
  829. long result;
  830. long count;
  831. long recordsReturned;
  832. long nextPos;
  833. long resultStatus;
  834. long presentStatus;
  835. any* refID;
  836. void* records;
  837. {
  838.   SearchResponseAPDU* query = (SearchResponseAPDU*)s_malloc((size_t)sizeof(SearchResponseAPDU));
  839.   query->PDUType = searchResponseAPDU;
  840.   query->SearchStatus = result;
  841.   query->ResultCount = count;
  842.   query->NumberOfRecordsReturned = recordsReturned;
  843.   query->NextResultSetPosition = nextPos;
  844.   query->ResultSetStatus = resultStatus;
  845.   query->PresentStatus = presentStatus;
  846.   query->ReferenceID = duplicateAny(refID);
  847.   query->DatabaseDiagnosticRecords = records;
  848.   return(query);  
  849. }
  850.  
  851. /*----------------------------------------------------------------------*/
  852.  
  853. void 
  854. freeSearchResponseAPDU(queryResponse)
  855. SearchResponseAPDU* queryResponse;
  856. {
  857.   freeAny(queryResponse->ReferenceID);
  858.   s_free(queryResponse);
  859. }
  860.  
  861. /*----------------------------------------------------------------------*/
  862.  
  863. char* 
  864. writeSearchResponseAPDU(queryResponse,buffer,len)
  865. SearchResponseAPDU* queryResponse;
  866. char* buffer;
  867. long* len;
  868. {
  869.   char* buf = buffer + HEADER_LEN; /* leave room for the header-length-indicator */
  870.   long size;
  871.  
  872.   RESERVE_SPACE_FOR_HEADER(len);
  873.   
  874.   buf = writePDUType(queryResponse->PDUType,buf,len);
  875.   buf = writeBinaryInteger(queryResponse->SearchStatus,(size_t)1,buf,len);
  876.   buf = writeBinaryInteger(queryResponse->ResultCount,(size_t)3,buf,len);
  877.   buf = writeBinaryInteger(queryResponse->NumberOfRecordsReturned,(size_t)3,buf,len);
  878.   buf = writeBinaryInteger(queryResponse->NextResultSetPosition,(size_t)3,buf,len);
  879.   buf = writeNum(queryResponse->ResultSetStatus,DT_ResultSetStatus,buf,len);
  880.   buf = writeNum(queryResponse->PresentStatus,DT_PresentStatus,buf,len);
  881.   buf = writeAny(queryResponse->ReferenceID,DT_ReferenceID,buf,len);
  882.     
  883.   /* go back and write the header-length-indicator */
  884.   RELEASE_HEADER_SPACE(len);
  885.   size = buf - buffer - HEADER_LEN; 
  886.   writeBinaryInteger(size,HEADER_LEN,buffer,len);
  887.  
  888.   if (queryResponse->DatabaseDiagnosticRecords != NULL)
  889.     buf = writeSearchResponseInfo(queryResponse,buf,len);    
  890.     
  891.   return(buf);
  892. }
  893.  
  894. /*----------------------------------------------------------------------*/
  895.  
  896. char* 
  897. readSearchResponseAPDU(queryResponse,buffer)
  898. SearchResponseAPDU** queryResponse;
  899. char* buffer;
  900. {
  901.   char* buf = buffer;
  902.   long size;
  903.   pdu_type pduType;
  904.   long result,count,recordsReturned,nextPos;
  905.   long resultStatus,presentStatus;
  906.   any *refID = NULL;
  907.   void* userInfo = NULL;
  908.   
  909.   /* read required part */
  910.   buf = readBinaryInteger(&size,HEADER_LEN,buf); 
  911.   buf = readPDUType(&pduType,buf);
  912.   buf = readBinaryInteger(&result,(size_t)1,buf);
  913.   buf = readBinaryInteger(&count,(size_t)3,buf);
  914.   buf = readBinaryInteger(&recordsReturned,(size_t)3,buf);
  915.   buf = readBinaryInteger(&nextPos,(size_t)3,buf);
  916.   
  917.   resultStatus = presentStatus = UNUSED;
  918.   refID = NULL;
  919.  
  920.   /* read optional part */
  921.   while (buf < (buffer + size + HEADER_LEN)) 
  922.     { data_tag tag = peekTag(buf);
  923.       switch (tag)
  924.     { case DT_ResultSetStatus:
  925.         buf = readNum(&resultStatus,buf);
  926.         break;
  927.       case DT_PresentStatus:
  928.         buf = readNum(&presentStatus,buf);
  929.         break;
  930.       case DT_ReferenceID:
  931.         buf = readAny(&refID,buf);
  932.         break;
  933.       default:
  934.         freeAny(refID);
  935.         REPORT_READ_ERROR(buf);
  936.         break;
  937.       }
  938.     }
  939.   
  940.   buf = readSearchResponseInfo(&userInfo,buf);
  941.   if (buf == NULL)
  942.     freeAny(refID);
  943.   RETURN_ON_NULL(buf);
  944.   
  945.   /* construct the search object */
  946.   *queryResponse = makeSearchResponseAPDU(result,count,recordsReturned,nextPos,
  947.                       (long)resultStatus,(long)presentStatus,refID,userInfo);
  948.  
  949.   freeAny(refID);
  950.   
  951.   return(buf);
  952. }
  953.  
  954.  
  955. /*
  956. **    Routines originally from ZUtil.c -- FM
  957. **
  958. **----------------------------------------------------------------------*/
  959. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  960.    No guarantees or restrictions.  See the readme file for the full standard
  961.    disclaimer.    
  962.   
  963.    3.26.90    Harry Morris, morris@think.com
  964.    3.30.90  Harry Morris - Changed any->bits to any->bytes
  965.    4.11.90  HWM - fixed include file names, changed 
  966.                    - writeCompressedIntegerWithPadding() to
  967.                   writeCompressedIntWithPadding()
  968.                 - generalized conditional includes (see c-dialect.h)
  969.    3.7.91   Jonny Goldman.  Replaced "short" in makeBitMap with "int" line 632.
  970. */
  971.  
  972. char* readErrorPosition = NULL; /* pos where buf stoped making sense */
  973.  
  974. /*----------------------------------------------------------------------*/
  975. /* A note on error handling 
  976.    read - these are low level routines, they do not check the type tags
  977.    which (sometimes) preceed the data (this is done by the higher
  978.    level functions which call these functions).  There is no 
  979.    attempt made to check that the reading does not exceed the read
  980.    buffer.  Such cases should be very rare and usually will be 
  981.    caught by the calling functions. (note - it is unlikely that 
  982.    a series of low level reads will go far off the edge without
  983.    triggering a type error.  However, it is possible for a single
  984.    bad read in an array function (eg. readAny) to attempt to read a 
  985.    large ammount, possibly causing a segmentation violation or out
  986.    of memory condition.
  987.  */
  988. /*----------------------------------------------------------------------*/
  989.  
  990. diagnosticRecord* 
  991. makeDiag(surrogate,code,addInfo)
  992. boolean surrogate;
  993. char* code;
  994. char* addInfo;
  995. {
  996.   diagnosticRecord* diag = 
  997.     (diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord));
  998.   
  999.   diag->SURROGATE = surrogate;
  1000.   memcpy(diag->DIAG,code,DIAGNOSTIC_CODE_SIZE);
  1001.   diag->ADDINFO = s_strdup(addInfo); 
  1002.  
  1003.   return(diag);
  1004. }
  1005.  
  1006. /*----------------------------------------------------------------------*/
  1007.  
  1008. void 
  1009. freeDiag(diag)
  1010. diagnosticRecord* diag;
  1011.   if (diag != NULL)
  1012.     { if (diag->ADDINFO != NULL)
  1013.     s_free(diag->ADDINFO);
  1014.     s_free(diag);
  1015.       }
  1016. }
  1017.  
  1018. /*----------------------------------------------------------------------*/
  1019.  
  1020. #define END_OF_RECORD    0x1D
  1021.  
  1022. char* 
  1023. writeDiag(diag,buffer,len)
  1024. diagnosticRecord* diag;
  1025. char* buffer;
  1026. long* len;
  1027. /* diagnostics (as per Appendix D) have a very weird format - this changes
  1028.    in SR-1
  1029.  */
  1030. {
  1031.   char* buf = buffer;
  1032.   long  length;
  1033.   
  1034.   if (diag == NULL)        /* handle unspecified optional args */
  1035.     return(buf);
  1036.  
  1037.   buf = writeTag(DT_DatabaseDiagnosticRecords,buf,len);
  1038.   CHECK_FOR_SPACE_LEFT(0,len);
  1039.   
  1040.   length = 3; 
  1041.   if (diag->ADDINFO != NULL)
  1042.     length += strlen(diag->ADDINFO);
  1043.     
  1044.   if (length >= 0xFFFF )    /* make sure the length is reasonable */
  1045.     { length = 0xFFFF - 1;
  1046.       diag->ADDINFO[0xFFFF - 3 - 1] = '\0';
  1047.     }
  1048.    
  1049.   buf = writeBinaryInteger(length,2,buf,len);
  1050.  
  1051.   CHECK_FOR_SPACE_LEFT(1,len);
  1052.   buf[0] = diag->DIAG[0]; 
  1053.   buf++;
  1054.   
  1055.   CHECK_FOR_SPACE_LEFT(1,len);
  1056.   buf[0] = diag->DIAG[1];
  1057.   buf++;
  1058.   
  1059.   if (length > 3)
  1060.     { CHECK_FOR_SPACE_LEFT(3,len);
  1061.       memcpy(buf,diag->ADDINFO,(size_t)length - 3);
  1062.       buf += length - 3;
  1063.     }
  1064.    
  1065.   CHECK_FOR_SPACE_LEFT(1,len);
  1066.   buf[0] = diag->SURROGATE;
  1067.   buf++;
  1068.   
  1069.   CHECK_FOR_SPACE_LEFT(1,len);
  1070.   buf[0] = END_OF_RECORD;
  1071.   buf++;
  1072.  
  1073.   return(buf);
  1074. }
  1075.  
  1076. /*----------------------------------------------------------------------*/
  1077.  
  1078. char* 
  1079. readDiag(diag,buffer)
  1080. diagnosticRecord** diag;
  1081. char* buffer;
  1082. {
  1083.   char* buf = buffer;
  1084.   diagnosticRecord* d 
  1085.     = (diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord));
  1086.   data_tag tag;
  1087.   long len;
  1088.   
  1089.   buf = readTag(&tag,buf);
  1090.   
  1091.   buf = readBinaryInteger(&len,2,buf);
  1092.   
  1093.   d->DIAG[0] = buf[0];
  1094.   d->DIAG[1] = buf[1];
  1095.   d->DIAG[2] = '\0';
  1096.     
  1097.   if (len > 3)
  1098.     { d->ADDINFO = (char*)s_malloc((size_t)(len - 3 + 1));
  1099.       memcpy(d->ADDINFO,(char*)(buf + 2),(size_t)(len - 3));
  1100.       d->ADDINFO[len - 3] = '\0';
  1101.     }
  1102.   else
  1103.     d->ADDINFO = NULL;
  1104.     
  1105.   d->SURROGATE = buf[len - 1];
  1106.   
  1107.   *diag = d;
  1108.  
  1109.   return(buf + len + 1);
  1110. }
  1111.  
  1112. /*----------------------------------------------------------------------*/
  1113.  
  1114. #define continueBit    0x80
  1115. #define dataMask    0x7F
  1116. #define dataBits    7
  1117.  
  1118. char*
  1119. writeCompressedInteger(num,buf,len)
  1120. unsigned long num;
  1121. char* buf;
  1122. long* len;
  1123. /* write a binary integer in the format described on p. 40.
  1124.    this might be sped up 
  1125. */
  1126. {
  1127.   char byte;
  1128.   long i;
  1129.   unsigned long size;
  1130.   
  1131.   size = writtenCompressedIntSize(num);
  1132.   CHECK_FOR_SPACE_LEFT(size,len);
  1133.   
  1134.   for (i = size - 1; i >= 0; i--)
  1135.     { byte = num & dataMask;
  1136.       if (i != (size-1))    /* turn on continue bit */
  1137.     byte = (char)(byte | continueBit);
  1138.       buf[i] = byte;
  1139.       num = num >> dataBits;    /* don't and here */
  1140.     }
  1141.    
  1142.   return(buf + size);
  1143.  
  1144. /*----------------------------------------------------------------------*/
  1145.  
  1146. char*
  1147. readCompressedInteger(num,buf)
  1148. unsigned long *num;
  1149. char* buf;
  1150. /* read a binary integer in the format described on p. 40.
  1151.    this might be sped up 
  1152. */
  1153. {
  1154.   long i = 0;
  1155.   unsigned char byte;
  1156.  
  1157.   *num = 0;
  1158.   
  1159.   do 
  1160.     { byte = buf[i++];
  1161.       *num = *num << dataBits;
  1162.       *num += (byte & dataMask);
  1163.     }
  1164.   while (byte & continueBit);
  1165.  
  1166.   return(buf + i);
  1167.  
  1168. /*----------------------------------------------------------------------*/
  1169.  
  1170. #define pad    128 /* high bit is set */
  1171.  
  1172. char*
  1173. writeCompressedIntWithPadding(num,size,buffer,len)
  1174. unsigned long num;
  1175. unsigned long size;
  1176. char* buffer;
  1177. long* len;
  1178. /* Like writeCompressedInteger, except writes padding (128) to make
  1179.    sure that size bytes are used.  This can be read correctly by 
  1180.    readCompressedInteger()
  1181. */
  1182. {
  1183.   char* buf = buffer;
  1184.   unsigned long needed,padding;
  1185.   long i;
  1186.     
  1187.   CHECK_FOR_SPACE_LEFT(size,len);
  1188.   
  1189.   needed = writtenCompressedIntSize(num);
  1190.   padding = size - needed;
  1191.   i = padding - 1;
  1192.  
  1193.   for (i = padding - 1;i >= 0;i--)
  1194.     { buf[i] = pad;
  1195.     }
  1196.   
  1197.   buf = writeCompressedInteger(num,buf + padding,len);
  1198.   
  1199.   return(buf);
  1200.  
  1201. /*----------------------------------------------------------------------*/
  1202.  
  1203. unsigned long
  1204. writtenCompressedIntSize(num)
  1205. unsigned long num;
  1206. /* return the number of bytes needed to represnet the value num in
  1207.    compressed format.  curently limited to 4 bytes
  1208.  */
  1209. {
  1210.   if (num < CompressedInt1Byte) 
  1211.     return(1);
  1212.   else if (num < CompressedInt2Byte) 
  1213.     return(2);
  1214.   else if (num < CompressedInt3Byte)
  1215.     return(3);
  1216.   else
  1217.     return(4);    
  1218. }
  1219.  
  1220. /*----------------------------------------------------------------------*/
  1221.  
  1222. char*
  1223. writeTag(tag,buf,len)
  1224. data_tag tag;
  1225. char* buf;
  1226. long* len;
  1227. /* write out a data tag */
  1228.   return(writeCompressedInteger(tag,buf,len));
  1229.  
  1230. /*----------------------------------------------------------------------*/
  1231.  
  1232. char*
  1233. readTag(tag,buf)
  1234. data_tag* tag;
  1235. char* buf;
  1236. /* read a data tag */
  1237.   return(readCompressedInteger(tag,buf));
  1238.  
  1239. /*----------------------------------------------------------------------*/
  1240.  
  1241. unsigned long 
  1242. writtenTagSize(tag)
  1243. data_tag tag;
  1244.   return(writtenCompressedIntSize(tag));
  1245. }
  1246.  
  1247. /*----------------------------------------------------------------------*/
  1248.  
  1249. data_tag
  1250. peekTag(buf)
  1251. char* buf;
  1252. /* read a data tag without advancing the buffer */
  1253. {
  1254.   data_tag tag;
  1255.   readTag(&tag,buf);
  1256.   return(tag);
  1257.  
  1258. /*----------------------------------------------------------------------*/
  1259.  
  1260. any* 
  1261. makeAny(size,data)
  1262. unsigned long size;
  1263. char* data;
  1264. {
  1265.   any* a = (any*)s_malloc((size_t)sizeof(any));
  1266.   a->size = size;
  1267.   a->bytes = data;
  1268.   return(a);
  1269. }
  1270.  
  1271. /*----------------------------------------------------------------------*/
  1272.  
  1273. void
  1274. freeAny(a)
  1275. any* a;
  1276. /* destroy an any and its associated data. Assumes a->bytes was
  1277.    allocated using the s_malloc family of libraries 
  1278.  */
  1279. {
  1280.   if (a != NULL)
  1281.     { if (a->bytes != NULL)
  1282.     s_free(a->bytes);
  1283.       s_free(a);
  1284.     }
  1285. }
  1286.  
  1287. /*----------------------------------------------------------------------*/
  1288.  
  1289. any* 
  1290. duplicateAny(a)
  1291. any* a;
  1292. {
  1293.   any* copy = NULL;
  1294.  
  1295.   if (a == NULL)
  1296.     return(NULL);
  1297.  
  1298.   copy = (any*)s_malloc((size_t)sizeof(any));
  1299.   copy->size = a->size;
  1300.   if (a->bytes == NULL)
  1301.     copy->bytes = NULL;
  1302.   else
  1303.     { copy->bytes = (char*)s_malloc((size_t)copy->size);
  1304.       memcpy(copy->bytes,a->bytes,(size_t)copy->size);
  1305.     }
  1306.   return(copy);
  1307. }
  1308.  
  1309. /*----------------------------------------------------------------------*/
  1310.  
  1311. char* 
  1312. writeAny(a,tag,buffer,len)
  1313. any* a;
  1314. data_tag tag;
  1315. char* buffer;
  1316. long* len;
  1317. /* write an any + tag and size info */
  1318. {
  1319.   char* buf = buffer;
  1320.  
  1321.   if (a == NULL)        /* handle unspecified optional args */
  1322.     return(buf);
  1323.   
  1324.   /* write the tags */
  1325.   buf = writeTag(tag,buf,len);
  1326.   buf = writeCompressedInteger(a->size,buf,len);
  1327.  
  1328.   /* write the bytes */
  1329.   CHECK_FOR_SPACE_LEFT(a->size,len);
  1330.   memcpy(buf,a->bytes,(size_t)a->size);
  1331.  
  1332.   return(buf+a->size);
  1333. }
  1334.  
  1335. /*----------------------------------------------------------------------*/
  1336.  
  1337.  
  1338. char *readAny(anAny,buffer)
  1339. any** anAny;
  1340. char* buffer;
  1341. /* read an any + tag and size info */
  1342. {
  1343.   char *buf;
  1344.   any* a;
  1345.   data_tag tag;
  1346.  
  1347.  
  1348.  
  1349. a=(any*)s_malloc((size_t)sizeof(any));
  1350.  
  1351.   buf=buffer;
  1352.   
  1353.   buf = readTag(&tag,buf);
  1354.   
  1355.   buf = readCompressedInteger(&a->size,buf);
  1356.  
  1357.   /* now simply copy the bytes */
  1358.   a->bytes = (char*)s_malloc((size_t)a->size);
  1359.   memcpy(a->bytes,buf,(size_t)a->size);
  1360.   *anAny = a;
  1361.  
  1362.   return(buf+a->size);
  1363. }
  1364.  
  1365. /*----------------------------------------------------------------------*/
  1366.  
  1367. unsigned long 
  1368. writtenAnySize(tag,a)
  1369. data_tag tag;
  1370. any* a;
  1371. {
  1372.   unsigned long size;
  1373.  
  1374.   if (a == NULL)
  1375.     return(0);
  1376.  
  1377.   size = writtenTagSize(tag);
  1378.   size += writtenCompressedIntSize(a->size);
  1379.   size += a->size;
  1380.   return(size);
  1381. }
  1382.  
  1383. /*----------------------------------------------------------------------*/
  1384.  
  1385. any*
  1386. stringToAny(s)
  1387. char* s;
  1388. {
  1389.   any* a = NULL;
  1390.   
  1391.   if (s == NULL)
  1392.     return(NULL);
  1393.     
  1394.   a = (any*)s_malloc((size_t)sizeof(any));
  1395.   a->size = strlen(s);
  1396.   a->bytes = (char*)s_malloc((size_t)a->size);
  1397.   memcpy(a->bytes,s,(size_t)a->size);
  1398.   return(a);
  1399. }
  1400.  
  1401. /*----------------------------------------------------------------------*/
  1402.  
  1403. char*
  1404. anyToString(a)
  1405. any* a;
  1406. {
  1407.   char* s = NULL;
  1408.   
  1409.   if (a == NULL)
  1410.     return(NULL);
  1411.     
  1412.   s = s_malloc((size_t)(a->size + 1));
  1413.   memcpy(s,a->bytes,(size_t)a->size);
  1414.   s[a->size] = '\0';
  1415.   return(s);
  1416. }
  1417.  
  1418. /*----------------------------------------------------------------------*/
  1419.  
  1420. char* 
  1421. writeString(s,tag,buffer,len)
  1422. char* s;
  1423. data_tag tag;
  1424. char* buffer;
  1425. long* len;
  1426. /* Write a C style string.  The terminating null is not written. 
  1427.    This function is not part of the Z39.50 spec.  It is provided
  1428.    for the convienience of those wishing to pass C strings in 
  1429.    the place of an any.
  1430.  */
  1431. {
  1432.   char* buf = buffer;
  1433.   any* data = NULL;
  1434.   if (s == NULL)
  1435.     return(buffer);        /* handle unused optional item before making an any */
  1436.   data = (any*)s_malloc((size_t)sizeof(any)); 
  1437.   data->size = strlen(s);
  1438.   data->bytes = s;        /* save a copy here by not using stringToAny() */
  1439.   buf = writeAny(data,tag,buf,len);
  1440.   s_free(data);            /* don't use freeAny() since it will free s too */
  1441.   return(buf);
  1442. }
  1443.  
  1444. /*----------------------------------------------------------------------*/
  1445.  
  1446. char* 
  1447. readString(s ,buffer)
  1448. char** s ;
  1449. char* buffer;
  1450. /* Read an any and convert it into a C style string.
  1451.    This function is not part of the Z39.50 spec.  It is provided
  1452.    for the convienience of those wishing to pass C strings in 
  1453.    the place of an any. 
  1454.  */
  1455. {
  1456.   any* data = NULL;
  1457.   char* buf = readAny(&data,buffer);
  1458.   *s = anyToString(data);
  1459.   freeAny(data);
  1460.   return(buf);
  1461. }
  1462.  
  1463. /*----------------------------------------------------------------------*/
  1464.  
  1465. unsigned long 
  1466. writtenStringSize(tag,s)
  1467. data_tag tag;
  1468. char* s;
  1469. {
  1470.   unsigned long size;
  1471.  
  1472.   if (s == NULL)
  1473.    return(0);
  1474.  
  1475.   size = writtenTagSize(tag);
  1476.   size += writtenCompressedIntSize(size);
  1477.   size += strlen(s);
  1478.   return(size);
  1479. }
  1480.  
  1481. /*----------------------------------------------------------------------*/
  1482.  
  1483. any* 
  1484. longToAny(num)
  1485. long num;
  1486. /* a convienience function */
  1487. {
  1488.   char s[40];
  1489.  
  1490.   sprintf(s,"%ld",num);
  1491.   
  1492.   return(stringToAny(s));
  1493. }
  1494.  
  1495. /*----------------------------------------------------------------------*/
  1496.  
  1497. long
  1498. anyToLong(a)
  1499. any* a;
  1500. /* a convienience function */
  1501. {
  1502.   long num;
  1503.   char* str = NULL;
  1504.   str = anyToString(a);
  1505.   sscanf(str,"%ld",&num);    /* could check the result and return
  1506.                    an error */
  1507.   s_free(str);
  1508.   return(num);
  1509. }
  1510.  
  1511. /*----------------------------------------------------------------------*/
  1512.  
  1513. #define bitsPerByte    8
  1514.  
  1515. bit_map*
  1516. makeBitMap(numBits)
  1517. unsigned long numBits;
  1518. /* construct and return a bitmap with numBits elements */
  1519. {
  1520.   va_list ap;
  1521.   long i,j;
  1522.   bit_map* bm = NULL;
  1523.  
  1524.   va_start(ap,numBits);
  1525.   
  1526.   bm = (bit_map*)s_malloc((size_t)sizeof(bit_map));
  1527.   bm->size = (unsigned long)ceil((double)numBits / bitsPerByte); 
  1528.   bm->bytes = (char*)s_malloc((size_t)bm->size);
  1529.   
  1530.   /* fill up the bits */
  1531.   for (i = 0; i < bm->size; i++) /* iterate over bytes */
  1532.     { char byte = 0;
  1533.       for (j = 0; j < bitsPerByte; j++) /* iterate over bits */
  1534.     { if ((i * bitsPerByte + j) < numBits)
  1535.         { boolean bit = false;
  1536.           bit = (boolean)va_arg(ap,boolean); 
  1537.           if (bit)
  1538.             { byte = byte | (1 << (bitsPerByte - j - 1));
  1539.             }
  1540.         }
  1541.       }
  1542.       bm->bytes[i] = byte;
  1543.     }
  1544.  
  1545.   va_end(ap);
  1546.   return(bm);
  1547. }
  1548.  
  1549.  
  1550. /*----------------------------------------------------------------------*/
  1551.  
  1552. void
  1553. freeBitMap(bm)
  1554. bit_map* bm;
  1555. /* destroy a bit map created by makeBitMap() */
  1556. {
  1557.   s_free(bm->bytes);
  1558.   s_free(bm);
  1559. }
  1560.  
  1561. /*----------------------------------------------------------------------*/
  1562.  
  1563. /* use this routine to interpret a bit map.  pos specifies the bit 
  1564.    number.  bit 0 is the Leftmost bit of the first byte.  
  1565.    Could do bounds checking.
  1566.  */
  1567.  
  1568. boolean
  1569. bitAtPos(pos,bm)
  1570. long pos;
  1571. bit_map* bm;
  1572. {
  1573.   if (pos > bm->size*bitsPerByte)
  1574.     return false;
  1575.   else
  1576.     return((bm->bytes[(pos / bitsPerByte)] & 
  1577.         (0x80>>(pos % bitsPerByte))) ?
  1578.        true : false);
  1579. }
  1580.  
  1581. /*----------------------------------------------------------------------*/
  1582.  
  1583. char*
  1584. writeBitMap(bm,tag,buffer,len)
  1585. bit_map* bm;
  1586. data_tag tag;
  1587. char* buffer;
  1588. long* len;
  1589. /* write a bitmap + type and size info */
  1590.   return(writeAny((any*)bm,tag,buffer,len));
  1591. }
  1592.  
  1593. /*----------------------------------------------------------------------*/
  1594.  
  1595. char*
  1596. readBitMap(bm,buffer)
  1597. bit_map** bm;
  1598. char* buffer;
  1599. /* read a bitmap + type and size info */
  1600. {
  1601.     char *c;
  1602.  
  1603.  
  1604.  
  1605. c=readAny((any**)bm,buffer);
  1606.  
  1607.   return(c);
  1608. }
  1609.  
  1610. /*----------------------------------------------------------------------*/
  1611.  
  1612. char* 
  1613. writeByte(byte,buf,len)
  1614. unsigned long byte;
  1615. char* buf;
  1616. long* len;
  1617. {
  1618.   CHECK_FOR_SPACE_LEFT(1,len);
  1619.   buf[0] = byte & 0xFF; /* we really only want the first byte */
  1620.   return(buf + 1);
  1621. }
  1622.  
  1623. /*----------------------------------------------------------------------*/
  1624.  
  1625. char* 
  1626. readByte(byte,buf)
  1627. unsigned char* byte;
  1628. char* buf;
  1629. {
  1630.   *byte = buf[0];
  1631.   return(buf + 1);
  1632. }
  1633.  
  1634. /*----------------------------------------------------------------------*/
  1635.  
  1636. char* 
  1637. writeBoolean(flag,buf,len)
  1638. boolean flag;
  1639. char* buf;
  1640. long* len;
  1641. {
  1642.   return(writeByte(flag,buf,len));
  1643. }
  1644.  
  1645. /*----------------------------------------------------------------------*/
  1646.  
  1647. char* 
  1648. readBoolean(flag,buffer)
  1649. boolean* flag;
  1650. char* buffer;
  1651. {
  1652.   unsigned char byte;
  1653.   char* buf = readByte(&byte,buffer);
  1654.   *flag = (byte == true) ? true : false;
  1655.   return(buf);
  1656. }
  1657.  
  1658. /*----------------------------------------------------------------------*/
  1659.  
  1660. char*
  1661. writePDUType(pduType,buf,len)
  1662. pdu_type pduType;
  1663. char* buf;
  1664. long* len;
  1665. /* PDUType is a single byte */
  1666. {
  1667.   return(writeBinaryInteger((long)pduType,(unsigned long)1,buf,len));
  1668.  
  1669. /*----------------------------------------------------------------------*/
  1670.  
  1671. char*
  1672. readPDUType(pduType,buf)
  1673. pdu_type* pduType;
  1674. char* buf;
  1675. /* PDUType is a single byte */
  1676. {
  1677.   return(readBinaryInteger((long*)pduType,(unsigned long)1,buf));
  1678.  
  1679. /*----------------------------------------------------------------------*/
  1680.  
  1681. pdu_type
  1682. peekPDUType(buf)
  1683. char* buf;
  1684. /* read the next pdu without advancing the buffer, Note that this 
  1685.    function is to be used on a buffer that is known to contain an
  1686.    APDU.  The pdu_type is written HEADER_LEN bytes into the buffer
  1687.  */
  1688. {
  1689.   pdu_type pdu;
  1690.   readPDUType(&pdu,buf + HEADER_LEN);
  1691.   return(pdu);
  1692. }
  1693.  
  1694. /*----------------------------------------------------------------------*/
  1695.  
  1696. #define BINARY_INTEGER_BYTES    sizeof(long) /* the number of bytes used by
  1697.                         a "binary integer" */
  1698. char*
  1699. writeBinaryInteger(num,size,buf,len)
  1700. long num;
  1701. unsigned long size;
  1702. char* buf;
  1703. long* len;
  1704. /* write out first size bytes of num - no type info
  1705.   XXX should this take unsigned longs instead ???  */
  1706. {
  1707.   long i;
  1708.   char byte;
  1709.  
  1710.   if (size < 1 || size > BINARY_INTEGER_BYTES)
  1711.     return(NULL);        /* error */
  1712.  
  1713.   CHECK_FOR_SPACE_LEFT(size,len);
  1714.  
  1715.   for (i = size - 1; i >= 0; i--)
  1716.     { byte = (char)(num & 255);
  1717.       buf[i] = byte;
  1718.       num = num >> bitsPerByte; /* don't and here */
  1719.     }
  1720.  
  1721.   return(buf + size);
  1722. }
  1723.  
  1724. /*----------------------------------------------------------------------*/
  1725.  
  1726. char*
  1727. readBinaryInteger(num,size,buf)
  1728. long* num;
  1729. unsigned long size;
  1730. char* buf;
  1731. /* read in first size bytes of num - no type info
  1732.   XXX this should take unsigned longs instead !!! */
  1733. {
  1734.   long i;
  1735.   unsigned char byte;
  1736.  
  1737.   if (size < 1 || size > BINARY_INTEGER_BYTES)
  1738.     return(buf);        /* error */
  1739.   *num = 0;
  1740.  
  1741.   for (i = 0; i < size; i++)
  1742.     { byte = buf[i];
  1743.       *num = *num << bitsPerByte;
  1744.       *num += byte;
  1745.     }
  1746.  
  1747.   return(buf + size);
  1748. }
  1749.  
  1750. /*----------------------------------------------------------------------*/
  1751.  
  1752. unsigned long 
  1753. writtenCompressedBinIntSize(num)
  1754. long num;
  1755. /* return the number of bytes needed to represent the value num.
  1756.    currently limited to max of 4 bytes 
  1757.    Only compresses for positive nums - negatives get whole 4 bytes
  1758.  */
  1759. {
  1760.   if (num < 0L)
  1761.     return(4);
  1762.   else if (num < 256L)        /* 2**8 */
  1763.     return(1);
  1764.   else if (num < 65536L)    /* 2**16 */
  1765.     return(2);
  1766.   else if (num < 16777216L)    /* 2**24 */
  1767.     return(3);
  1768.   else
  1769.     return(4);
  1770. }
  1771.  
  1772. /*----------------------------------------------------------------------*/
  1773.  
  1774. char*
  1775. writeNum(num,tag,buffer,len)
  1776. long num;
  1777. data_tag tag;
  1778. char* buffer;
  1779. long* len;
  1780. /* write a binary integer + size and tag info */
  1781. {
  1782.   char* buf = buffer;
  1783.   long size = writtenCompressedBinIntSize(num);
  1784.   
  1785.   if (num == UNUSED)
  1786.     return(buffer);
  1787.     
  1788.   buf = writeTag(tag,buf,len);
  1789.   buf = writeCompressedInteger(size,buf,len); 
  1790.   buf = writeBinaryInteger(num,(unsigned long)size,buf,len); 
  1791.   return(buf);
  1792. }
  1793.  
  1794. /*----------------------------------------------------------------------*/
  1795.  
  1796. char*
  1797. readNum(num,buffer)
  1798. long* num;
  1799. char* buffer;
  1800. /* read a binary integer + size and tag info */
  1801. {
  1802.   char* buf = buffer;
  1803.   data_tag tag;
  1804.   unsigned long size;
  1805.   unsigned long val;
  1806.   
  1807.   buf = readTag(&tag,buf);
  1808.   buf = readCompressedInteger(&val,buf);
  1809.   size = (unsigned long)val;
  1810.   buf = readBinaryInteger(num,size,buf);
  1811.   return(buf);
  1812. }
  1813.  
  1814. /*----------------------------------------------------------------------*/
  1815.  
  1816. unsigned long 
  1817. writtenNumSize(tag,num)
  1818. data_tag tag;
  1819. long num;
  1820. {
  1821.   long dataSize = writtenCompressedBinIntSize(num);
  1822.   long size;
  1823.   
  1824.   size = writtenTagSize(tag); /* space for the tag */
  1825.   size += writtenCompressedIntSize(dataSize); /* space for the size */
  1826.   size += dataSize; /* space for the data */
  1827.   
  1828.   return(size);
  1829. }
  1830.  
  1831. /*----------------------------------------------------------------------*/
  1832.  
  1833. typedef void (voidfunc)();
  1834.  
  1835. void
  1836. doList(list,func)
  1837. void** list;
  1838. voidfunc *func;
  1839. /* call func on each element of the NULL terminated list of pointers */
  1840. {
  1841.   register long i;
  1842.   register void* ptr = NULL;
  1843.   if (list == NULL)
  1844.     return;
  1845.   for (i = 0,ptr = list[i]; ptr != NULL; ptr = list[++i])
  1846.     (*func)(ptr);
  1847. }
  1848.  
  1849. /*----------------------------------------------------------------------*/
  1850.  
  1851. char* 
  1852. writeProtocolVersion(buf,len)
  1853. char* buf;
  1854. long* len;
  1855. /* write a bitmap describing the protocols available */
  1856. {
  1857.   static bit_map* version = NULL;
  1858.  
  1859.   if (version == NULL)
  1860.    { version = makeBitMap((unsigned long)1,true); /* version 1! */
  1861.    }
  1862.     
  1863.   return(writeBitMap(version,DT_ProtocolVersion,buf,len));
  1864. }
  1865.  
  1866. /*----------------------------------------------------------------------*/
  1867.  
  1868. char*
  1869. defaultImplementationID()
  1870. {
  1871.   static char    ImplementationID[] = "TMC";
  1872.   return(ImplementationID);
  1873. }
  1874.  
  1875. /*----------------------------------------------------------------------*/
  1876.  
  1877. char*
  1878. defaultImplementationName()
  1879. {
  1880.   static char ImplementationName[] = "Thinking Machines Corporation Z39.50";
  1881.   return(ImplementationName);
  1882. }
  1883.  
  1884. /*----------------------------------------------------------------------*/
  1885.  
  1886. char*
  1887. defaultImplementationVersion()
  1888. {
  1889.   static char    ImplementationVersion[] = "2.0A";
  1890.   return(ImplementationVersion);
  1891. }
  1892.  
  1893. /*----------------------------------------------------------------------*/
  1894.  
  1895.  
  1896. /*
  1897. **    Routines originally from ZType1.c -- FM
  1898. **
  1899. **----------------------------------------------------------------------*/
  1900. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  1901.    No guarantees or restrictions.  See the readme file for the full standard
  1902.    disclaimer.    
  1903.   
  1904.    3.26.90    Harry Morris, morris@think.com
  1905.    4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  1906. */
  1907. /*----------------------------------------------------------------------*/
  1908.  
  1909. query_term*
  1910. makeAttributeTerm(use,
  1911.           relation,
  1912.           position,
  1913.           structure,
  1914.           truncation,
  1915.           completeness,
  1916.           term)
  1917. char* use;
  1918. char* relation;
  1919. char* position;
  1920. char* structure;
  1921. char* truncation;
  1922. char* completeness;
  1923. any* term;
  1924. {
  1925.   query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term));
  1926.  
  1927.   qt->TermType = TT_Attribute;
  1928.  
  1929.   /* copy in the attributes */
  1930.   strncpy(qt->Use,use,ATTRIBUTE_SIZE);
  1931.   strncpy(qt->Relation,relation,ATTRIBUTE_SIZE);
  1932.   strncpy(qt->Position,position,ATTRIBUTE_SIZE);
  1933.   strncpy(qt->Structure,structure,ATTRIBUTE_SIZE);
  1934.   strncpy(qt->Truncation,truncation,ATTRIBUTE_SIZE);
  1935.   strncpy(qt->Completeness,completeness,ATTRIBUTE_SIZE);
  1936.  
  1937.   qt->Term = duplicateAny(term);
  1938.  
  1939.   qt->ResultSetID = NULL;
  1940.  
  1941.   return(qt);
  1942. }
  1943.  
  1944. /*----------------------------------------------------------------------*/
  1945.  
  1946. query_term*
  1947. makeResultSetTerm(resultSet)
  1948. any* resultSet;
  1949.   query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term));
  1950.  
  1951.   qt->TermType = TT_ResultSetID;
  1952.  
  1953.   qt->ResultSetID = duplicateAny(resultSet);
  1954.  
  1955.   qt->Term = NULL;
  1956.   
  1957.   return(qt);
  1958. }
  1959.  
  1960. /*----------------------------------------------------------------------*/
  1961.  
  1962. query_term* 
  1963. makeOperatorTerm(operatorCode)
  1964. char* operatorCode;
  1965. {
  1966.   query_term* qt = (query_term*)s_malloc((size_t)sizeof(query_term));
  1967.  
  1968.   qt->TermType = TT_Operator;
  1969.  
  1970.   strncpy(qt->Operator,operatorCode,OPERATOR_SIZE);
  1971.  
  1972.   qt->Term = NULL;
  1973.   qt->ResultSetID = NULL;
  1974.  
  1975.   return(qt);
  1976. }
  1977.  
  1978. /*----------------------------------------------------------------------*/
  1979.  
  1980. void 
  1981. freeTerm(qt)
  1982. query_term* qt;
  1983. {
  1984.   switch (qt->TermType)
  1985.     { case TT_Attribute:
  1986.     freeAny(qt->Term);
  1987.     break;
  1988.       case TT_ResultSetID:
  1989.     freeAny(qt->ResultSetID);
  1990.     break;
  1991.       case TT_Operator:
  1992.     /* do nothing */
  1993.     break;
  1994.       default:
  1995.     panic("Implementation error: Unknown term type %ld",
  1996.           qt->TermType);
  1997.     break;
  1998.       }
  1999.   s_free(qt);
  2000. }
  2001.  
  2002. /*----------------------------------------------------------------------*/
  2003.  
  2004. #define ATTRIBUTE_LIST_SIZE    ATTRIBUTE_SIZE * 6
  2005. #define AT_DELIMITER    " "
  2006.  
  2007. char* 
  2008. writeQueryTerm(qt,buffer,len)
  2009. query_term* qt;
  2010. char* buffer;
  2011. long* len;
  2012. {
  2013.   char* buf = buffer;
  2014.   char attributes[ATTRIBUTE_LIST_SIZE];
  2015.  
  2016.   switch (qt->TermType)
  2017.     { case TT_Attribute:
  2018.     strncpy(attributes,qt->Use,ATTRIBUTE_LIST_SIZE); 
  2019.     s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE);
  2020.     s_strncat(attributes,qt->Relation,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); 
  2021.     s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE);
  2022.     s_strncat(attributes,qt->Position,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); 
  2023.     s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE);
  2024.     s_strncat(attributes,qt->Structure,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); 
  2025.     s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE);
  2026.     s_strncat(attributes,qt->Truncation,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE); 
  2027.     s_strncat(attributes,AT_DELIMITER,sizeof(AT_DELIMITER) + 1,ATTRIBUTE_LIST_SIZE);
  2028.     s_strncat(attributes,qt->Completeness,ATTRIBUTE_SIZE,ATTRIBUTE_LIST_SIZE);
  2029.     buf = writeString(attributes,DT_AttributeList,buf,len);
  2030.     buf = writeAny(qt->Term,DT_Term,buf,len);
  2031.     break;
  2032.       case TT_ResultSetID:
  2033.     buf = writeAny(qt->ResultSetID,DT_ResultSetID,buf,len);
  2034.     break;
  2035.       case TT_Operator:
  2036.     buf = writeString(qt->Operator,DT_Operator,buf,len);
  2037.     break;
  2038.       default:
  2039.     panic("Implementation error: Unknown term type %ld",
  2040.           qt->TermType);
  2041.     break;
  2042.       }
  2043.  
  2044.   return(buf);
  2045. }
  2046.  
  2047. /*----------------------------------------------------------------------*/
  2048.  
  2049. char* 
  2050. readQueryTerm(qt,buffer)
  2051. query_term** qt;
  2052. char* buffer;
  2053. {
  2054.   char* buf = buffer;
  2055.   char  *attributeList = NULL;
  2056.   char* operator = NULL;
  2057.   any*     term;
  2058.   char* use = NULL;
  2059.   char* relation = NULL;
  2060.   char* position = NULL;
  2061.   char* structure = NULL;
  2062.   char* truncation = NULL;
  2063.   char* completeness;
  2064.   any*    resultSetID = NULL;
  2065.   data_tag tag;
  2066.  
  2067.   
  2068.   tag = peekTag(buffer);
  2069.  
  2070.   switch(tag)
  2071.     { case DT_AttributeList:
  2072.     buf = readString(&attributeList,buf);
  2073.     buf = readAny(&term,buf);
  2074.     use = strtok(attributeList,AT_DELIMITER);
  2075.     relation = strtok(NULL,AT_DELIMITER);
  2076.     position = strtok(NULL,AT_DELIMITER);
  2077.     structure = strtok(NULL,AT_DELIMITER);
  2078.     truncation = strtok(NULL,AT_DELIMITER);
  2079.     completeness = strtok(NULL,AT_DELIMITER);
  2080.     *qt = makeAttributeTerm(use,relation,position,structure,
  2081.                 truncation,completeness,term);
  2082.     s_free(attributeList);
  2083.     freeAny(term);
  2084.     break;
  2085.       case DT_ResultSetID:
  2086.     buf = readAny(&resultSetID,buf);
  2087.     *qt = makeResultSetTerm(resultSetID);    
  2088.     freeAny(resultSetID);
  2089.     break;
  2090.       case DT_Operator:
  2091.     buf = readString(&operator,buf);
  2092.     *qt = makeOperatorTerm(operator);
  2093.     s_free(operator);
  2094.     break;
  2095.       default:
  2096.     REPORT_READ_ERROR(buf);
  2097.     break;
  2098.       }
  2099.   
  2100.   return(buf);
  2101. }
  2102.  
  2103. /*----------------------------------------------------------------------*/
  2104.  
  2105. static unsigned long getQueryTermSize _AP((query_term* qt));
  2106.  
  2107. static unsigned long
  2108. getQueryTermSize(qt)
  2109. query_term* qt;
  2110. /* figure out how many bytes it will take to write this query */
  2111. {
  2112.   unsigned long size;
  2113.   static char attributes[] = "11 22 33 44 55 66"; /* we just need this to 
  2114.                              calculate its written
  2115.                              size */
  2116.  
  2117.   switch (qt->TermType)
  2118.     { case TT_Attribute:
  2119.     size = writtenStringSize(DT_AttributeList,attributes);
  2120.     size += writtenAnySize(DT_Term,qt->Term);
  2121.     break;
  2122.       case TT_ResultSetID:
  2123.     size = writtenAnySize(DT_ResultSetID,qt->ResultSetID);
  2124.     break;
  2125.       case TT_Operator:
  2126.     size = writtenStringSize(DT_Operator,qt->Operator);
  2127.     break;
  2128.       default:
  2129.     panic("Implementation error: Unknown term type %ld",
  2130.           qt->TermType);
  2131.     break;
  2132.       }
  2133.  
  2134.   return(size);
  2135. }
  2136.  
  2137. /*----------------------------------------------------------------------*/
  2138.  
  2139. /* A query is simply a null terminated list of query terms. For 
  2140.    transmission, a query is written into an any which is sent as
  2141.    the user information field. */
  2142.  
  2143. any*
  2144. writeQuery(terms)
  2145. query_term** terms;
  2146. {
  2147.   any* info = NULL;
  2148.   char* writePos = NULL;
  2149.   char* data = NULL;
  2150.   unsigned long size = 0;
  2151.   long remaining = 0;
  2152.   long i;
  2153.   query_term* qt = NULL;
  2154.  
  2155.   if (terms == NULL)
  2156.     return(NULL);
  2157.  
  2158.   /* calculate the size of write buffer */
  2159.   for (i = 0,qt = terms[i]; qt != NULL; qt = terms[++i])
  2160.     size += getQueryTermSize(qt);
  2161.  
  2162.   data = (char*)s_malloc((size_t)size);
  2163.  
  2164.   /* write the terms */
  2165.   writePos = data;
  2166.   remaining = size;
  2167.   for (i = 0,qt = terms[i]; qt != NULL; qt = terms[++i])
  2168.     writePos = writeQueryTerm(qt,writePos,&remaining);
  2169.  
  2170.   info = makeAny(size,data);
  2171.  
  2172.   return(info);
  2173. }
  2174.  
  2175. /*----------------------------------------------------------------------*/
  2176.  
  2177. query_term**
  2178. readQuery(info)
  2179. any *info;
  2180. {
  2181.   char* readPos = info->bytes;
  2182.   query_term** terms = NULL;
  2183.   query_term* qt = NULL;
  2184.   long numTerms = 0L;
  2185. char tmp[100];
  2186.  
  2187. sprintf(tmp,"readquery: bytes: %ld",info->size);
  2188. log_write(tmp);
  2189.  
  2190.   while (readPos < info->bytes + info->size)
  2191.     { readPos = readQueryTerm(&qt,readPos);
  2192.  
  2193.       if (terms == NULL)
  2194.     { terms = (query_term**)s_malloc((size_t)(sizeof(query_term*)*2));
  2195.     }
  2196.       else
  2197.     { terms = 
  2198.         (query_term**)s_realloc((char*)terms,
  2199.                     (size_t)(sizeof(query_term*)*(numTerms+2)));
  2200.       }
  2201. if(qt==NULL)
  2202.     log_write("qt = null");
  2203.       terms[numTerms++] = qt;
  2204.       terms[numTerms] = NULL;
  2205.     }
  2206.  
  2207.   return(terms);
  2208. }
  2209.  
  2210. /*----------------------------------------------------------------------*/
  2211.  
  2212.  
  2213. /*
  2214. **    Routines originally from panic.c -- FM
  2215. **
  2216. **----------------------------------------------------------------------*/
  2217. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2218.    No guarantees or restrictions.  See the readme file for the full standard
  2219.    disclaimer.
  2220.  
  2221.    Morris@think.com
  2222. */
  2223.  
  2224. /* panic is an error system interface.  On the Mac, it will pop
  2225.  * up a little window to explain the problem.
  2226.  * On a unix box, it will print out the error and call perror()
  2227.  */
  2228.  
  2229. /*----------------------------------------------------------------------*/
  2230.  
  2231. static void exitAction _AP((long error));
  2232.  
  2233. static void
  2234. exitAction(error)
  2235. long error;
  2236. {
  2237.   long i;
  2238.   for (i = 0; i < 100000; i++)
  2239.     ;
  2240.   exit(0);
  2241. }
  2242.  
  2243. /*----------------------------------------------------------------------*/
  2244.  
  2245. #define PANIC_HEADER "Fatal Error:  "
  2246.  
  2247. void
  2248. panic(format)
  2249. char* format;
  2250. {
  2251.   va_list ap;            /* the variable arguments */
  2252.  
  2253.   fprintf(stderr,PANIC_HEADER);
  2254.   va_start(ap, format);        /* init ap */
  2255.   vfprintf(stderr,format,ap);    /* print the contents */
  2256.   va_end(ap);            /* free ap */
  2257.   fflush(stderr);
  2258.   
  2259.   exitAction(0);
  2260. }
  2261.  
  2262. /*----------------------------------------------------------------------*/
  2263.  
  2264.  
  2265. /*
  2266. **    Routines originally from cutil.c -- FM
  2267. **
  2268. **----------------------------------------------------------------------*/
  2269. /* Wide AREA INFORMATION SERVER SOFTWARE    
  2270.    No guarantees or restrictions.  See the readme file for the full standard
  2271.    disclaimer.  
  2272.   
  2273.    3.26.90    Harry Morris, morris@think.com
  2274.    4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  2275. */
  2276.  
  2277. #include <varargs.h>
  2278.  
  2279.  
  2280. /*----------------------------------------------------------------------*/
  2281.  
  2282. void
  2283. fs_checkPtr(ptr)
  2284. void* ptr;
  2285. /* If the ptr is NULL, give an error */
  2286.   if (ptr == NULL)
  2287.     panic("checkPtr found a NULL pointer");
  2288. }
  2289.  
  2290. /*----------------------------------------------------------------------*/
  2291.  
  2292. void*
  2293. fs_malloc(size)
  2294. size_t size;
  2295. /* does safety checks and optional accounting */
  2296.   register void* ptr = NULL;
  2297.  
  2298.   ptr = (void*)calloc((size_t)size,(size_t)1);
  2299.   s_checkPtr(ptr);
  2300.   
  2301.   return(ptr);
  2302. }
  2303.  
  2304. /*----------------------------------------------------------------------*/
  2305.  
  2306. void*
  2307. fs_realloc(ptr,size)
  2308. void* ptr;
  2309. size_t size;
  2310. /* does safety checks and optional accounting 
  2311.    note - we don't know how big ptr's memory is, so we can't ensure
  2312.    that any new memory allocated is NULLed!
  2313.  */
  2314.   register void* nptr = NULL;
  2315.   
  2316.   if (ptr == NULL)        /* this is really a malloc */
  2317.     return(s_malloc(size));
  2318.     
  2319.   nptr = (void*)realloc(ptr,size);
  2320.   s_checkPtr(ptr);
  2321.    
  2322.   return(nptr);
  2323. }
  2324.  
  2325. /*----------------------------------------------------------------------*/
  2326.  
  2327. void
  2328. fs_free(ptr)
  2329. void* ptr;
  2330. /* does safety checks and optional accounting */
  2331. {
  2332.   if (ptr != NULL)        /* some non-ansi compilers/os's cant handle freeing null */
  2333.     {                /* if we knew the size of this block of memory, we could clear it - oh well */
  2334.       free(ptr);
  2335.     }
  2336. }
  2337.  
  2338. /*----------------------------------------------------------------------*/
  2339.  
  2340. char*
  2341. s_strdup(s)
  2342. char* s;
  2343.  
  2344. /* return a copy of s.  This is identical to the standard library routine
  2345.    strdup(), except that it is safe.  If s == NULL or malloc fails, 
  2346.    appropriate action is taken.
  2347.  */
  2348. {
  2349.   unsigned long len;
  2350.   char* copy = NULL;
  2351.   
  2352.   if (s == NULL)        /* saftey check to postpone stupid errors */
  2353.     return(NULL);
  2354.     
  2355.   len = strlen(s);        /* length of string - terminator */
  2356.   copy = (char*)s_malloc((size_t)(sizeof(char)*(len + 1)));
  2357.   strncpy(copy,s,len + 1);
  2358.   return(copy);
  2359. }
  2360.  
  2361. /*----------------------------------------------------------------------*/
  2362.  
  2363. char*
  2364. fs_strncat(dst,src,maxToAdd,maxTotal)
  2365. char* dst;
  2366.    char* src;
  2367.    size_t maxToAdd;
  2368.    size_t maxTotal;
  2369.  
  2370. /* like strncat, except the fourth argument limits the maximum total 
  2371.    length of the resulting string
  2372.  */
  2373. {
  2374.   size_t dstSize = strlen(dst);
  2375.   size_t srcSize = strlen(src);
  2376.   
  2377.   if (dstSize + srcSize < maxTotal) /* use regular old strncat */
  2378.     return(strncat(dst,src,maxToAdd));
  2379.   else
  2380.     { size_t truncateTo = maxTotal - dstSize - 1;
  2381.       char   saveChar = src[truncateTo];
  2382.       char*  result = NULL;
  2383.       src[truncateTo] = '\0';
  2384.       result = strncat(dst,src,maxToAdd);
  2385.       src[truncateTo] = saveChar;
  2386.       return(result);
  2387.     }
  2388. }
  2389.  
  2390. /*----------------------------------------------------------------------*/
  2391.  
  2392. char char_downcase(long_ch)
  2393. unsigned long long_ch;
  2394. {
  2395.   unsigned char ch = long_ch & 0xFF; /* just want one byte */
  2396.   /* when ansi is the way of the world, this can be tolower */
  2397.   return (((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' -'A') : ch);
  2398. }
  2399.  
  2400. char *string_downcase(word)
  2401. char *word;
  2402. {
  2403.   long i = 0;
  2404.   while(word[i] != '\0'){
  2405.     word[i] = char_downcase((unsigned long)word[i]);
  2406.     i++;
  2407.   }
  2408.   return(word);
  2409. }
  2410.  
  2411. /*----------------------------------------------------------------------*/
  2412.  
  2413.